const fs = require("fs");
const path = require("path");
const { execSync } = require("child_process");
const { getFirstFileNameWithoutExt, prepareTempDirectory } = require("./utils/common");
const config = JSON.parse(fs.readFileSync(path.join(__dirname, "..", "config.json"), "utf8"));
const { generateWordASSFromFile } = require("./utils/wordAssGenerator");
const { mergeAssFilesWithWordPriority } = require("./utils/assMerger");
const { processFirstFrame } = require("./create_video_with_ffmpeg");
const encodeFormat = config.encodeFormat || "h264_nvenc";

const tempFiles = [];
const { FFMPEG_PATH } = require("./utils/ffmpeg");
const { mergeVideosOrderedByList, mergeAudioVideo, mergeAssVideo } = require("./utils/videoProcessor");
async function main() {
  const tempDir = path.join(__dirname, "../temp_ffmpeg");
  console.log("  tempDir:", tempDir);
  prepareTempDirectory(tempDir);
  // 获取config.inputDirDat 下的第一个字幕文件ass文件x.ass
  console.log("  获取config.inputDirDat 下的第一个字幕文件ass文件...");
  const lineFileNameInDatDir = getFirstFileNameWithoutExt(config.inputDirDat, ".ass");
  const lineFileFullPathInDatDir = path.join(config.inputDirDat, `${lineFileNameInDatDir}.ass`);
  const lineFileInTemp = path.join(config.outputDirSrt, `${lineFileNameInDatDir}.ass`);
  fs.copyFileSync(lineFileFullPathInDatDir, lineFileInTemp);
  // 根据ass文件生成单词字幕x_word.ass
  console.log("  生成单词字幕文件...");
  let wordAssFile = path.join(config.outputDirSrt, `${lineFileNameInDatDir}_words.ass`);
  tempFiles.push(wordAssFile);
  await generateWordASSFromFile(lineFileFullPathInDatDir, wordAssFile, config.projectSettings.wordStyles);
  // 将字幕x.ass和x_word.ass合并形成新字幕x_new.ass
  console.log("  合并字幕和单词字幕文件...");
  const mergedAssFile = `${lineFileInTemp}_new.ass`;
  tempFiles.push(mergedAssFile);

  await mergeAssFilesWithWordPriority(lineFileInTemp, wordAssFile, mergedAssFile);

  // 获取config.inputDirMp3 下的第一个视频文件mp4文件
  const videoFileName = getFirstFileNameWithoutExt(config.inputDirMp3, ".mp4");
  const videoFileFullPath = path.join(config.inputDirMp3, `${videoFileName}.mp4`);
  console.log("  获取到视频文件...", videoFileFullPath);
  // 将视频裁切为规定的比例尺
  const outputFileCuted = `${tempDir}/${videoFileName}_cutted.mp4`;
  tempFiles.push(outputFileCuted);
  console.log("  裁切视频为系统设定比例尺...");
  processVideo(videoFileFullPath, outputFileCuted);
  console.log("  视频裁切成功，输出文件为：", outputFileCuted);
  // 将视频和音频合并为带有字幕的视频 new.mp4
  const outputFileCuttedAndMergedAss = path.join(config.outputDirVideo, `${videoFileName}.mp4`);
  tempFiles.push(outputFileCuttedAndMergedAss);
  console.log("  合并视频和字幕...");
  const mergeSubtitleSuccess = mergeAssVideo(outputFileCuted, mergedAssFile, outputFileCuttedAndMergedAss);
  console.log(`  mergeSubtitleSuccess:`, mergeSubtitleSuccess);
  if (mergeSubtitleSuccess) {
    console.log(`  合并字幕成功，输出文件为：${outputFileCuttedAndMergedAss}`);
  } else {
    console.warn(`  合并字幕失败，请检查字幕文件是否正确`);
  }
  // 获取config.inputStartVoice对应的音频文件
  const startVoicePath = path.join(__dirname, "..", config.inputStartVoice);
  tempFiles.push(startVoicePath);
  console.log(`  开始语音文件为：${startVoicePath}`);
  // 获取第一帧图片并添加文字
  console.log(`  处理首帧图片...`);
  // 处理首帧图片
  const outputDir = path.join(__dirname, "../output");
  console.log(`  输出目录为：${outputDir}`);
  let firstFrameWithTextPath = null;
  const customTitle = `${config.title}`;
  const titleFilePath = path.join(__dirname, "../temp/", "temp_title.txt");
  console.log(`  设置视频标题: ${customTitle}`);
  fs.writeFileSync(titleFilePath, customTitle, "utf-8");
  async function addTxt2FirstFrame() {
    console.log(`  1. 处理首帧图片...`);
    firstFrameWithTextPath = await processFirstFrame(outputDir);
    console.log(`  2. 处理完成，图片保存在：${firstFrameWithTextPath}`);
  }

  await addTxt2FirstFrame();

  console.log(`  处理完成，首帧图片保存在：${firstFrameWithTextPath}`);
  if (!firstFrameWithTextPath) {
    console.log(`  没有有效的首帧图片，请检查输入参数或处理过程。`);
    process.exit(1);
  }

  // 将第一帧图片转化为视频V1
  console.log("  Processing first frame...");

  const firstFrameOutputPath = path.join(tempDir, `img_first.mp4`);
  tempFiles.push(firstFrameOutputPath);
  // 从配置文件获取视频尺寸
  let configVideoWidth = 1920;
  let configVideoHeight = 1080;
  try {
    configVideoWidth = config.projectSettings.videoWidth || 1920;
    configVideoHeight = config.projectSettings.videoHeight || 1080;
  } catch (error) {
    console.warn("无法加载配置文件，使用默认尺寸:", error.message);
  }
  const firstFrameDuration = config.projectSettings.firstFrameDuration || 0.5;
  // 使用FFmpeg将图片转换为视频，保持正确的宽高比
  try {
    const convertCommand = `"${FFMPEG_PATH}" -y -loglevel quiet -loop 1 -i "${firstFrameWithTextPath}" -vf "scale=w=${configVideoWidth}:h=${configVideoHeight}:force_original_aspect_ratio=decrease,crop=w=min(${configVideoWidth}\\,iw):h=min(${configVideoHeight}\\,ih):x=(iw-min(${configVideoWidth}\\,iw))/2:y=(ih-min(${configVideoHeight}\\,ih))/2,pad=w=${configVideoWidth}:h=${configVideoHeight}:x=(ow-iw)/2:y=(oh-ih)/2:color=black" -c:v ${encodeFormat} -t ${firstFrameDuration} -pix_fmt yuv420p -r 30 "${firstFrameOutputPath}"`;
    execSync(convertCommand);
  } catch (error) {
    console.error("  图片转换为视频时出错:", error.message);
    process.exit(1);
  }

  // 将音频startVoicePath和V1合并 m1.mp4
  console.log("  Merging audio and video...");
  const tempVideoWithoutAss = path.join(tempDir, "temp_video_withoutAss.mp4");
  tempFiles.push(tempVideoWithoutAss);
  console.log("  tempVideoWithoutAss 1 :", tempVideoWithoutAss);
  const mergeSuccess = mergeAudioVideo(firstFrameOutputPath, startVoicePath, tempVideoWithoutAss, firstFrameDuration);
  console.log("  tempVideoWithoutAss 2 :", tempVideoWithoutAss);
  if (mergeSuccess) {
    console.log("  合并开始语音文件到视频中成功");
  } else {
    console.warn("  合并开始语音文件到视频中失败");
    process.exit(1);
  }
  // 将m1.mp4 和 new.mp4合并为output.mp4
  console.log("  Merging video and start video...");
  const outputFileWithStart = path.join(config.outputDirVideo, `${videoFileName}_withStart.mp4`);
  tempFiles.push(outputFileWithStart);
  // mergeVideosOrdered([tempVideoWithoutAss, outputFileCuttedAndMergedAss], outputFileWithStart);
  const listFile = path.join(tempDir, "list.txt");
  tempFiles.push(listFile);
  const outputFileCuttedAndMergedAssAbsPath = path.resolve(outputFileCuttedAndMergedAss);
  const listContent = `file ${tempVideoWithoutAss.replace(/\\/g, "/")}\nfile ${outputFileCuttedAndMergedAssAbsPath.replace(/\\/g, "/")}`;
  console.log(`  listFile: ${listContent}`);
  fs.writeFileSync(listFile, listContent,{encoding: 'utf-8'});

  mergeVideosOrderedByList(listFile.replace(/\\/g, "/"), outputFileWithStart);
  console.log("  Merging video and start video success, output file:", outputFileWithStart);
}
/**
 * 将视频进行裁切：
 * 裁切比例为config.projectSettings.videoWidth / config.projectSettings.videoHeight  
 * 具体方法为：  
 * 1. 获取视频的宽高  
 * 2. 如果视频高度大于videoHeight且视频宽度大于videoWidth，则先进性缩小
 * 3. 如果视频高度小于videoHeight且视频宽度小于videoWidth，则先进行放大
 * - 注意2、 或者3 不是直接缩放到config.projectSettings.videoWidth / config.projectSettings.videoHeight 
 * - 而是通过缩放到满足如下条件之一：
 * - a. 宽度大于videoWidth ，且高度不小于videoHeight
 * - b. 高度大于videoHeight ，且宽度不小于videoWidth
 * 4. 从2、或者3步骤得到的视频，进行从四周裁切，使得大小等于videoWidth 和 videoHeight
 * @param {string} videoPath - 视频路径
 * @param {string} outputFile - 输出文件路径
 */
function processVideo(videoPath,outputFile){
  const w = config.projectSettings.videoWidth;
  const h = config.projectSettings.videoHeight;
  
  // 先获取视频的原始尺寸
  const probeCommand = `"${FFMPEG_PATH}" -i "${videoPath}" 2>&1 | findstr "Stream.*Video"`;
  let videoInfo;
  try {
    videoInfo = execSync(probeCommand, { encoding: 'utf-8' });
  } catch (error) {
    console.error("  获取视频信息时出错:", error.message);
    process.exit(1);
  }
  
  // 从输出中解析视频尺寸，例如：1920x1080
  const dimensionMatch = videoInfo.match(/(\d{3,5})x(\d{3,5})/);
  if (!dimensionMatch) {
    console.error("  无法解析视频尺寸信息");
    process.exit(1);
  }
  
  const originalWidth = parseInt(dimensionMatch[1]);
  const originalHeight = parseInt(dimensionMatch[2]);
  console.log(`  原始视频尺寸: ${originalWidth}x${originalHeight}`);
  
  // 构建处理命令，确保至少一个维度达到或超过目标尺寸
  let command;
  if (originalHeight > h && originalWidth > w) {
    // 如果视频高度大于videoHeight且视频宽度大于videoWidth，则缩小
    console.log("  视频尺寸大于目标尺寸，进行缩小处理");
    // 使用force_original_aspect_ratio=decrease缩放，然后裁剪
    command = `"${FFMPEG_PATH}" -y -i "${videoPath}" -loglevel quiet -vf "scale=w=${w}:h=${h}:force_original_aspect_ratio=decrease,crop=w=${w}:h=${h},setsar=1/1" -c:v ${encodeFormat} -preset medium -crf 23 -pix_fmt yuv420p -an "${outputFile}"`;
  } else {
    // 其他情况都需要放大处理
    console.log("  视频尺寸小于等于目标尺寸，进行放大处理");
    // 先放大到至少一个维度达到目标尺寸
    // 然后裁剪到精确的目标尺寸
    command = `"${FFMPEG_PATH}" -y -i "${videoPath}" -loglevel quiet -vf "scale=w=${w}:h=${h}:force_original_aspect_ratio=increase,crop=w=${w}:h=${h},setsar=1/1" -c:v ${encodeFormat} -preset medium -crf 23 -pix_fmt yuv420p -an "${outputFile}"`;
  }
  
  try{
    execSync(command, { stdio: 'inherit' });
  }catch(error){
    console.error("  视频处理时出错:", error.message);
    process.exit(1);
  }finally{
    for (const file of tempFiles) {
      if (fs.existsSync(file)) {
        fs.unlinkSync(file);
      }
    }
  }
}
main();
